package com.k.kc.util;

import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.util.Objects;

/**
 * 基本数据类型转换
 *
 * 支持大小端序 BigEndian  LittleEndian
 * 一般操作系统都是小端，而通讯协议是大端的。
 *
 * @author kivil
 */

public enum BasicTypeConverter {
    /**
     * 1字节 8位
     */
    BYTEARRAY {
        public short toShortBig(byte[] b) {
            return (short) (((b[0] << 8) | b[1] & 0xff));
        }
        public short toShortLittle(byte[] b) {
            return (short) (((b[1] << 8) | b[0] & 0xff));
        }
        public int toIntBigEndian(byte[] b) {
            return b[3] & 0xff
                    | (b[2] & 0xff) << 8
                    | (b[1] & 0xff) << 16
                    | (b[0] & 0xff) << 24;
        }
        public int toIntLittleEndian(byte[] b) {
            return b[0] & 0xff
                    | (b[1] & 0xff) << 8
                    | (b[2] & 0xff) << 16
                    | (b[3] & 0xff) << 24;
        }
        public long toLongLittle(byte[] b) {
            return ((((long) b[0] & 0xff))
                    | (((long) b[1] & 0xff) << 8)
                    | (((long) b[2] & 0xff) << 16)
                    | (((long) b[3] & 0xff) << 24)
                    | (((long) b[4] & 0xff) << 32)
                    | (((long) b[5] & 0xff) << 40)
                    | (((long) b[6] & 0xff) << 48)
                    | (((long) b[7] & 0xff) << 56));
        }

        public long toLongBig(byte[] b) {
            return ((((long) b[0] & 0xff) << 56)
                    | (((long) b[1] & 0xff) << 48)
                    | (((long) b[2] & 0xff) << 40)
                    | (((long) b[3] & 0xff) << 32)
                    | (((long) b[4] & 0xff) << 24)
                    | (((long) b[5] & 0xff) << 16)
                    | (((long) b[6] & 0xff) << 8)
                    | (((long) b[7] & 0xff)));
        }
        public String toString(byte[] bytes, Charset charset) {
            if (Objects.isNull(charset)) {
                return new String(bytes, StandardCharsets.UTF_8);
            }
            return new String(bytes, charset);
        }
    },
    /**
     * 2 字节 16位
     */
    SHORT {
        public byte[] toByteArrayBig(short n) {
            byte[] b = new byte[2];
            b[1] = (byte) (n & 0xff);
            b[0] = (byte) (n >> 8 & 0xff);
            return b;
        }

        /**
         * 将short转为低字节在前，高字节在后的byte数组(小端)
         * @param n short
         * @return byte[]
         */
        public byte[] toByteArrayLittle(short n) {
            byte[] b = new byte[2];
            b[0] = (byte) (n & 0xff);
            b[1] = (byte) (n >> 8 & 0xff);
            return b;
        }

    },

    /**
     * 4字节32位
     */
    INT {
        public byte[] toByteArrayBigEndian(int a) {
            byte[] b = new byte[4];
            b[3] = (byte) (a & 0xff);
            b[2] = (byte) (a >> 8 & 0xff);
            b[1] = (byte) (a >> 16 & 0xff);
            b[0] = (byte) (a >> 24 & 0xff);
            return b;
        }

        public byte[] toByteArrayLittleEndian(int a) {
            byte[] b = new byte[4];
            b[0] = (byte) (a & 0xff);
            b[1] = (byte) (a >> 8 & 0xff);
            b[2] = (byte) (a >> 16 & 0xff);
            b[3] = (byte) (a >> 24 & 0xff);
            return b;
        }
    },


    /**
     * 4 字节 32 位
     */
    FLOAT {
        public byte[] toByteArray(float f) {
            int value = Float.floatToRawIntBits(f);
            byte[] byteRet = new byte[4];
            for (int i = 0; i < 4; i++) {
                byteRet[i] = (byte) ((value >> 8 * i) & 0xff);
            }
            return byteRet;
        }
    },
    /**
     * 8字节 64位
     */
    LONG {
        /**
         * long类型转byte[] (大端)
         * @param n long
         * @return byte array
         */
        public byte[] toByteArrayBig(long n) {
            byte[] b = new byte[8];
            b[7] = (byte) (n & 0xff);
            b[6] = (byte) (n >> 8 & 0xff);
            b[5] = (byte) (n >> 16 & 0xff);
            b[4] = (byte) (n >> 24 & 0xff);
            b[3] = (byte) (n >> 32 & 0xff);
            b[2] = (byte) (n >> 40 & 0xff);
            b[1] = (byte) (n >> 48 & 0xff);
            b[0] = (byte) (n >> 56 & 0xff);
            return b;
        }

        /**
         * long类型转byte[] (小端)
         * @param n long
         * @return byte array
         */
        public byte[] toByteArrayLittle(long n) {
            byte[] b = new byte[8];
            b[0] = (byte) (n & 0xff);
            b[1] = (byte) (n >> 8 & 0xff);
            b[2] = (byte) (n >> 16 & 0xff);
            b[3] = (byte) (n >> 24 & 0xff);
            b[4] = (byte) (n >> 32 & 0xff);
            b[5] = (byte) (n >> 40 & 0xff);
            b[6] = (byte) (n >> 48 & 0xff);
            b[7] = (byte) (n >> 56 & 0xff);
            return b;
        }
    },
    DOUBLE {
        public byte[] toByteArray(double d) {
            long value = Double.doubleToRawLongBits(d);
            byte[] byteRet = new byte[8];
            for (int i = 0; i < 8; i++) {
                byteRet[i] = (byte) ((value >> 8 * i) & 0xff);
            }
            return byteRet;
        }
    },

    /**
     * 2 字节 16 位
     */
    CHAR {
        public byte[] toByteArrayLittle(char c){
            byte[] b = new byte[2];
            b[1] = (byte) ((c & 0xFF00) >> 8);
            b[0] = (byte) (c & 0xFF);
            return b;
        }
        public byte[] toByteArrayBig(char c){
            byte[] b = new byte[2];
            b[0] = (byte) ((c & 0xFF00) >> 8);
            b[1] = (byte) (c & 0xFF);
            return b;
        }
        public byte[] toByteArray(char[] chars) {
            Charset cs = StandardCharsets.UTF_8;
            CharBuffer cb = CharBuffer.allocate(chars.length);
            cb.put(chars);
            cb.flip();
            ByteBuffer bb = cs.encode(cb);
            return bb.array();
        }
    },

    /**
     * 1 字节 8 位
     */
    BOOLEAN {
        public Boolean toBoolean(boolean bool){
            return bool;
        }
    },

    /**
     * 无字节序
     * 只有编码处理 UTF-16，UTF-8，ISO-8859-1
     * UTF-8没有字节序。你可以阅读更多[这里]（http://stackoverflow.com/questions/3833693/isn-t-on-big-endian-machines-utf-8s-byte-order-different-than-on-little-endian） ，
     * 但基本上，如果在同一个单词中同时读取多个字节，字节顺序就很重要。
     * UTF-8被定义为只是一个字节流，没有多字节字;即使是需要多个字节的代码点也是以多个1字节的字来定义的。
     * 所以作为一个读写器，你只需要处理“下一个字节，下一个字节，下一个字节”，在这种情况下，字节序不是一个因素。 – yshavit
     * UTF-8是面向字节的，因此不存在关于结尾的问题。第一个字节总是第一个字节，第二个字节总是第二个，等等，而不考虑尾数。
     */
    STRING {
        public byte[] toByteArray(String str, Charset charset) {
            if (Objects.isNull(charset)) {
                return str.getBytes(StandardCharsets.UTF_8);
            }
            return str.getBytes(charset);
        }
        public boolean toBoolean(String s){
            return Boolean.parseBoolean(s);
        }
    };

    static final int BYTE_SIZE_1 = 1;
    static final int BYTE_SIZE_2 = 2;
    static final int BYTE_SIZE_4 = 4;
    static final int BYTE_SIZE_8 = 8;
}
